﻿using EFCore.BulkExtensions;
using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using iWare.Wms.Core;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Linq.Dynamic.Core;

namespace iWare.Wms.Application
{
    /// <summary>
    /// 库位服务
    /// </summary>
    [Route("api/WareLocation")]
    [ApiDescriptionSettings("仓库基础数据", Name = "Location", Order = 100)]

    public class WareLocationService : ControllerBase, IDynamicApiController, ITransient
    {
        private readonly IRepository<WareArea, MasterDbContextLocator> _wareAreaRep; //所属库区仓储
        private readonly IRepository<WareLocation, MasterDbContextLocator> _wareLocationRep; //库位仓储
        private readonly IRepository<WareLocationVsContainer, MasterDbContextLocator> _wareLocationVsContainerRep; //库位与容器关系仓储
        private readonly IRepository<v_ware_location, MasterDbContextLocator> _v_ware_locationRep; //库位试图仓储

        #region 默认
        /// <summary>
        /// 默认
        /// </summary>
        /// <param name="wareAreaRep"></param>
        /// <param name="wareLocationRep"></param>
        /// <param name="wareLocationVsContainerRep"></param>
        /// <param name="v_ware_locationRep"></param>
        public WareLocationService(
            IRepository<WareArea, MasterDbContextLocator> wareAreaRep,
            IRepository<WareLocation, MasterDbContextLocator> wareLocationRep,
            IRepository<WareLocationVsContainer, MasterDbContextLocator> wareLocationVsContainerRep,
            IRepository<v_ware_location, MasterDbContextLocator> v_ware_locationRep
        )
        {
            _wareAreaRep = wareAreaRep;
            _wareLocationRep = wareLocationRep;
            _wareLocationVsContainerRep = wareLocationVsContainerRep;
            _v_ware_locationRep = v_ware_locationRep;
        }
        #endregion

        /// <summary>
        /// 分页查询库位
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("page")]
        public async Task<PageResult<WareLocationOutput>> Page([FromQuery] WareLocationSearch input)
        {
            var result = await _v_ware_locationRep.DetachedEntities
                .Where(input.AreaID != -10, u => u.AreaID == input.AreaID)
                .Where(input.LocationStatus != LocationStatusEnum.all, u => u.LocationStatus == input.LocationStatus)
                .Where(input.AreaID != -10, u => u.Attribute == input.Attribute)
                .Where(input.IsLock != YesOrNot.All, u => u.IsLock == input.IsLock)
                .Where(input.IsEmptyContainer != YesOrNot.All, u => u.IsEmptyContainer == input.IsEmptyContainer)
                .Where(input.IsVirtual != YesOrNot.All, u => u.IsVirtual == input.IsVirtual)
                .Where(!string.IsNullOrEmpty(input.Code), u => EF.Functions.Like(u.Code, $"%{input.Code.Trim()}%"))
                //.Where(input.WareTwo != null && input.WareTwo != "ALL", u => EF.Functions.Like(u.WareTwo, $"%{input.WareTwo.Trim()}%"))
                .OrderBy(PageInputOrder.OrderBuilder<WareLocationSearch>(input))
                .ProjectToType<WareLocationOutput>()
                .ToADPagedListAsync(input.PageNo, input.PageSize);

            foreach (var item in result.Rows)
            {
                var areaModel = await _wareAreaRep.FirstOrDefaultAsync(n => n.Id == item.AreaID);
                if (areaModel != null) item.AreaName = areaModel.AreaName;
            }

            return result;
        }

        /// <summary>
        /// 获取可用库位    需要根据库区获取对应的可用库位
        /// </summary>
        /// <returns></returns>
        [NonAction]
        public async Task<WareLocation> GetLocation()
        {
            //获取已经被占用的库位信息
            return await _wareLocationRep.Where(p => p.LocationStatus == LocationStatusEnum.kongxian).FirstOrDefaultAsync();
        }

        /// <summary>
        /// 根据库位编号检测库位
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("check")]
        public async Task CheckLocation([FromQuery] WareLocationSearch input)
        {
            bool isExist = await _wareLocationVsContainerRep
                .AnyAsync(z => z.WareLocation.Code == input.Code);
            if (isExist) throw Oops.Oh("该库位正在使用中，请重新操作");
        }

        /// <summary>
        /// 根据规则生成库位信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("AddLocation")]
        public async Task AddLocation([FromBody] WareLocationInput input)
        {
            var WareOne = "W"; //所属企业
            var WareTwo = "1"; //所属产区
            //根据库区ID获取库区类型
            var pList = new List<WareLocation>();
            var areaModel = await _wareAreaRep.FirstOrDefaultAsync(n => n.Id == input.AreaID);
            if (areaModel.Id == 374444777422917 || areaModel.Id == 374444736143429)
            {
                for (int j = 1; j <= input.ColumnNo; j++)
                {
                    for (int f = 1; f <= input.LayerNo; f++)
                    {
                        for (int h = 1; h <= input.DeepcellNo; h++)
                        {
                            var itemmodel = new WareLocation()
                            {
                                WareOne = WareOne,
                                WareTwo = WareTwo,
                                AreaID = input.AreaID,
                                WareThree = areaModel.AreaType.ToString(),
                                Aisle = input.Aisle, //货架
                                RowNo = input.RowNo, //排
                                ColumnNo = j, //列
                                LayerNo = f, //层
                                DeepcellNo = h,
                                Code = String.Format("{0}{1}{2}{3}{4}{5}{6}", WareOne, WareTwo, areaModel.AreaType.ToString(), input.Aisle, input.RowNo, j, f, h),
                                LocationStatus = LocationStatusEnum.kongxian,
                            };

                            var isExit = await _wareLocationRep.AnyAsync(p => p.Code == itemmodel.Code);
                            if (!isExit) pList.Add(itemmodel);
                        }
                    }
                }

                //批量新增 通过 Nuget 安装 EFCore.BulkExtensions 包即可。
                await _wareLocationRep.Context.BulkInsertAsync(pList);
            }
        }

        /// <summary>
        /// 删除库位信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("DeleteLocation")]
        public async Task DeleteLocation([FromBody] DeleteWareLocationInput input)
        {
            var model = await _wareLocationRep.FirstOrDefaultAsync(p => p.Id == input.Id);
            if (model != null && model.LocationStatus == LocationStatusEnum.kongxian) await _wareLocationRep.DeleteAsync(model);
            else throw Oops.Oh("该库位正在使用中，请重新操作");
        }
        /// <summary>
        /// 批量锁定库位
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("AddLock")]
        public async Task AddLock([FromBody] IsLockWareLocationInput input)
        {
            int length = input.Ids.Count;
            for (int i = 0; i < length; i++)
            {
                long Id = input.Ids[i];
                var model = await _wareLocationRep.FirstOrDefaultAsync(p => p.Id == Id);
                if (model != null && model.IsLock == YesOrNot.N)
                {
                    model.IsLock = YesOrNot.Y;
                    await _wareLocationRep.UpdateAsync(model);
                }
            }
        }

        /// <summary>
        /// 批量解锁库位
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("DelLock")]
        public async Task DelLock([FromBody] IsLockWareLocationInput input)
        {
            int length = input.Ids.Count;
            for (int i = 0; i < length; i++)
            {
                long Id = input.Ids[i];
                var model = await _wareLocationRep.FirstOrDefaultAsync(p => p.Id == Id);
                if (model != null && model.IsLock == YesOrNot.Y)
                {
                    model.IsLock = YesOrNot.N;
                    await _wareLocationRep.UpdateAsync(model);
                }
            }
        }

        #region 系统生成多种库位信息
        /// <summary>
        /// 系统生成平库
        /// </summary>
        /// <returns></returns>
        [HttpGet("locationByPK")]
        public async Task ProductLocationByPK()
        {
            var WareOne = "W"; //所属企业
            var WareTwo = "1"; //所属产区

            //根据库区ID获取库区类型
            var pList = new List<WareLocation>();
            var wareArea = await _wareAreaRep.FirstOrDefaultAsync(n => n.AreaName.Contains("平库"));

            for (int j = 1; j <= 41; j++) //排：41；列：5；层：1
            {
                for (int f = 1; f <= 5; f++)
                {
                    var itemmodel = new WareLocation()
                    {
                        WareOne = WareOne,
                        WareTwo = WareTwo,
                        AreaID = wareArea.Id,
                        WareThree = wareArea.AreaType.ToString(),
                        Aisle = 1, //货架
                        RowNo = j, //排
                        ColumnNo = f, //列
                        LayerNo = 1, //层
                        DeepcellNo = 1,
                        Code = String.Format("{0}{1}{2}{3}{4}{5}{6}", WareOne, WareTwo, wareArea.AreaType.ToString(), j.ToString("00"), f, 1, 1),
                        LocationStatus = LocationStatusEnum.kongxian,
                        CreatedTime = DateTimeOffset.Now
                    };

                    var isExit = await _wareLocationRep.AnyAsync(p => p.Code == itemmodel.Code);
                    if (!isExit) pList.Add(itemmodel);
                }
                //}
                //批量新增 通过 Nuget 安装 EFCore.BulkExtensions 包即可。
            }
            await _wareLocationRep.Context.BulkInsertAsync(pList);
        }

        /// <summary>
        /// 系统生成装配库
        /// </summary>
        /// <returns></returns>
        [HttpGet("locationByZQK")]
        public async Task ProductLocationByZQ()
        {
            var LaneList = new List<string> { "01A", "01B", "01C", "02A", "02B", "02C" };
            var WareOne = "W";
            var WareTwo = "1";
            var WareThree = "ZQ";

            var ZQList = new List<WareLocation>();
            foreach (var item in LaneList)
            {
                for (int i = 1; i < 10; i++)
                {
                    var itemmodel = new WareLocation()
                    {
                        WareOne = WareOne,
                        WareTwo = WareTwo,
                        WareThree = WareThree,
                        //Lane = item,
                        Code = String.Format("{0}{1}{2}{3}{4}", WareOne, WareTwo, WareThree, item, i),
                        //Parameter1 = item.Substring(1, 1),
                        //Parameter2 = item.Substring(2, 1),
                        //Parameter3 = i.ToString(),
                        CreatedTime = DateTimeOffset.Now
                    };
                    ZQList.Add(itemmodel);
                }
            }

            //批量新增 通过 Nuget 安装 EFCore.BulkExtensions 包即可。
            await _wareLocationRep.Context.BulkInsertAsync(ZQList);
        }

        /// <summary>
        /// 系统生成公共库
        /// </summary>
        /// <returns></returns>
        [HttpGet("locationByGGK")]
        public async Task ProductLocationByGGK()
        {
            var wareArea = await _wareAreaRep.FirstOrDefaultAsync(n => n.AreaName.Contains("公共库"));
            var WareOne = "U";
            var WareTwo = "1";
            var WareThree = "R";
            var lane = "";
            var gList = new List<WareLocation>();
            for (int i = 1; i <= 1; i++)
            {
                //lane = i < 10 ? "0" + i : i.ToString();
                for (int j = 1; j <= 3; j++)
                {
                    for (int f = 1; f <= 2; f++)
                    {
                        var itemmodel = new WareLocation()
                        {
                            AreaID = wareArea.Id,
                            WareOne = WareOne,
                            WareTwo = WareTwo,
                            WareThree = WareThree,
                            Aisle = 1, //巷道
                            RowNo = i, //排
                            ColumnNo = j, //列
                            LayerNo = f, //层
                            Code = String.Format("{0}{1}{2}{3}{4}{5}{6}", WareOne, WareTwo, WareThree, 1, j, f, 1), //货架层列位
                            CreatedTime = DateTimeOffset.Now
                        };
                        gList.Add(itemmodel);
                    }
                }
            }

            //批量新增 通过 Nuget 安装 EFCore.BulkExtensions 包即可。
            await _wareLocationRep.Context.BulkInsertAsync(gList);
        }

        /// <summary>
        /// 系统生成普通库
        /// </summary>
        /// <returns></returns>
        [HttpGet("locationByPTK")]
        public async Task ProductLocationByPTK()
        {
            var WareOne = "W"; //所属企业
            var WareTwo = "1"; //所属产区
            var WareThree = "P"; //所属库区
            var lane = "";
            var pList = new List<WareLocation>();
            for (int i = 1; i <= 9; i++) //货架1-9
            {
                lane = i < 10 ? "0" + i : i.ToString();

                if (i == 1 || i == 6 || i == 7) //货架1、6、7（一共5层和一共2列）
                {
                    for (int j = 1; j <= 2; j++) //列
                    {
                        for (int f = 1; f <= 5; f++) //层
                        {
                            var itemmodel = new WareLocation()
                            {
                                AreaID = 358871162105925, //所属库区
                                WareOne = WareOne,
                                WareTwo = WareTwo,
                                WareThree = WareThree,
                                Aisle = 1, //巷道
                                RowNo = i, //排
                                ColumnNo = j, //列
                                LayerNo = f, //层
                                Code = String.Format("{0}{1}{2}{3}{4}{5}{6}", WareOne, WareTwo, WareThree, 1, i, j, f), //货架层列位
                                CreatedTime = DateTimeOffset.Now
                            };
                            pList.Add(itemmodel);
                        }
                    }
                }
                else //货架2、3、4、5、8、9（一共5层和一共3列）
                {
                    for (int j = 1; j <= 3; j++) //列
                    {
                        for (int f = 1; f <= 5; f++) //层
                        {
                            var itemmodel = new WareLocation()
                            {
                                AreaID = 358871162105925, //所属库区
                                WareOne = WareOne,
                                WareTwo = WareTwo,
                                WareThree = WareThree,
                                Aisle = 1, //巷道
                                RowNo = i, //排
                                ColumnNo = j, //列
                                LayerNo = f, //层
                                Code = String.Format("{0}{1}{2}{3}{4}{5}{6}", WareOne, WareTwo, WareThree, 1, i, j, f), //货架层列位
                                CreatedTime = DateTimeOffset.Now
                            };
                            pList.Add(itemmodel);
                        }
                    }
                }
            }

            for (int i = 10; i <= 15; i++) //货架10-15
            {
                lane = i < 10 ? "0" + i : i.ToString();

                if (i == 12 || i == 13) //货架12、13（一共4层和一共2列）
                {
                    for (int j = 1; j <= 2; j++) //列
                    {
                        for (int f = 1; f <= 4; f++) //层
                        {
                            var itemmodel = new WareLocation()
                            {
                                AreaID = 358871162105925, //所属库区
                                WareOne = WareOne,
                                WareTwo = WareTwo,
                                WareThree = WareThree,
                                Aisle = 1, //巷道
                                RowNo = i, //排
                                ColumnNo = j, //列
                                LayerNo = f, //层
                                Code = String.Format("{0}{1}{2}{3}{4}{5}{6}", WareOne, WareTwo, WareThree, 1, i, j, f), //货架层列位
                                CreatedTime = DateTimeOffset.Now
                            };
                            pList.Add(itemmodel);
                        }
                    }
                }
                else //货架10、11、14、15（一共4层和一共3列）
                {
                    for (int j = 1; j <= 3; j++) //列
                    {
                        for (int f = 1; f <= 4; f++) //层
                        {
                            var itemmodel = new WareLocation()
                            {
                                AreaID = 358871162105925, //所属库区
                                WareOne = WareOne,
                                WareTwo = WareTwo,
                                WareThree = WareThree,
                                Aisle = 1, //巷道
                                RowNo = i, //排
                                ColumnNo = j, //列
                                LayerNo = f, //层
                                Code = String.Format("{0}{1}{2}{3}{4}{5}{6}", WareOne, WareTwo, WareThree, 1, i, j, f), //货架层列位
                                CreatedTime = DateTimeOffset.Now
                            };
                            pList.Add(itemmodel);
                        }
                    }
                }
            }

            for (int i = 16; i <= 20; i++) //货架16-20
            {
                lane = i < 10 ? "0" + i : i.ToString();

                if (i == 20)//货架20（一共4层和一共5列）
                {
                    for (int j = 1; j <= 5; j++) //列
                    {
                        for (int f = 1; f <= 4; f++) //层
                        {
                            var itemmodel = new WareLocation()
                            {
                                AreaID = 358871162105925, //所属库区
                                WareOne = WareOne,
                                WareTwo = WareTwo,
                                WareThree = WareThree,
                                Aisle = 1, //巷道
                                RowNo = i, //排
                                ColumnNo = j, //列
                                LayerNo = f, //层
                                Code = String.Format("{0}{1}{2}{3}{4}{5}{6}", WareOne, WareTwo, WareThree, 1, i, j, f), //货架层列位
                                CreatedTime = DateTimeOffset.Now
                            };
                            pList.Add(itemmodel);
                        }
                    }
                }
                else //货架16、17、18、19（一共5层和一共5列）
                {
                    for (int j = 1; j <= 5; j++) //列
                    {
                        for (int f = 1; f <= 5; f++) //层
                        {
                            var itemmodel = new WareLocation()
                            {
                                AreaID = 358871162105925, //所属库区
                                WareOne = WareOne,
                                WareTwo = WareTwo,
                                WareThree = WareThree,
                                Aisle = 1, //巷道
                                RowNo = i, //排
                                ColumnNo = j, //列
                                LayerNo = f, //层
                                Code = String.Format("{0}{1}{2}{3}{4}{5}{6}", WareOne, WareTwo, WareThree, 1, i, j, f), //货架层列位
                                CreatedTime = DateTimeOffset.Now
                            };
                            pList.Add(itemmodel);
                        }
                    }
                }
            }

            //批量新增 通过 Nuget 安装 EFCore.BulkExtensions 包即可。
            await _wareLocationRep.Context.BulkInsertAsync(pList);
        }

        /// <summary>
        /// 系统生成立体库
        /// </summary>
        /// <returns></returns>
        [HttpGet("locationByLTK")]
        public async Task ProductLocationByLTK()
        {
            var DArea = await _wareAreaRep.FirstOrDefaultAsync(n => n.AreaName.Contains("立体库"));
            var WareOne = "W";
            var WareTwo = "1";
            var WareThree = "L";
            //var Lane = "";
            var pList = new List<WareLocation>();
            for (int i = 1; i < 2; i++)   //排
            {
                for (int j = 1; j < 10; j++)   //列
                {
                    for (int f = 1; f < 10; f++)   //层
                    {
                        //for (int u = 1; u < 10; u++)   //个
                        //{
                        var itemmodel = new WareLocation()
                        {
                            AreaID = DArea.Id,
                            WareOne = WareOne,
                            WareTwo = WareTwo,
                            WareThree = WareThree,
                            Aisle = 1, //巷道
                            RowNo = i, //排
                            ColumnNo = j, //列
                            LayerNo = f, //层
                            Code = String.Format("{0}{1}{2}{3}{4}{5}{6}", WareOne, WareTwo, WareThree, 1, j, f, 1), //货架层列位
                            CreatedTime = DateTimeOffset.Now
                        };
                        pList.Add(itemmodel);
                        //}
                    }
                }
            }

            //批量新增 通过 Nuget 安装 EFCore.BulkExtensions 包即可。
            await _wareLocationRep.Context.BulkInsertAsync(pList);
        }

        /// <summary>
        /// 系统生成南京虚拟库位
        /// </summary>
        /// <returns></returns>
        [HttpGet("locationByXNK")]
        public async Task ProductLocationByXN()
        {
            var DArea = await _wareAreaRep.FirstOrDefaultAsync(n => n.AreaName.Contains("南京库位"));
            var WareOne = "N";
            var WareTwo = "1";
            var WareThree = "X";
            //var Lane = "";
            var pList = new List<WareLocation>();
            for (int i = 1; i <= 10; i++)   //排
            {
                for (int j = 1; j <= 100; j++)   //列
                {
                    var itemmodel = new WareLocation()
                    {
                        AreaID = DArea.Id,
                        WareOne = WareOne,
                        WareTwo = WareTwo,
                        WareThree = WareThree,
                        Aisle = 1, //巷道
                        RowNo = i, //排
                        ColumnNo = j, //列
                        LayerNo = 1, //层
                        Code = String.Format("{0}{1}{2}{3}{4}", WareOne, WareTwo, WareThree, i.ToString("000"), j.ToString("000")), //货架层列位
                        IsVirtual = YesOrNot.Y,
                        CreatedTime = DateTimeOffset.Now
                    };
                    pList.Add(itemmodel);
                }
            }

            //批量新增 通过 Nuget 安装 EFCore.BulkExtensions 包即可。
            await _wareLocationRep.Context.BulkInsertAsync(pList);
        }
        #endregion

        /// <summary>
        /// 更新库位重量、库位属性
        /// </summary>
        /// <returns></returns>
        [HttpPost("UpdateLocation")]
        public async Task UpdateLocation(UpdateLocationInput input)
        {
            if (input.AreaId == 374444843716677) //一楼立体库
            {
                var wareLocationList = await _wareLocationRep.DetachedEntities.Where(u => u.AreaID == input.AreaId).ToListAsync();

                foreach (var item in wareLocationList)
                {
                    //承重
                    item.Heavy = "1T";

                    // 高度、库位属性
                    if (item.LayerNo == 1 || item.LayerNo == 2)   //1、2层：500
                    {
                        item.High = 500;
                        item.Attribute = "小";
                    }
                    else if (item.LayerNo == 3 || item.LayerNo == 4 || item.LayerNo == 5) //3、4、5层：800
                    {
                        item.High = 800;
                        item.Attribute = "中";
                    }
                    //if (item.LayerNo == 3 || item.LayerNo == 4 || item.LayerNo == 5)    //6、7层：1200
                    else
                    {
                        item.High = 1200;
                        item.Attribute = "大";
                    }

                    await _wareLocationRep.UpdateAsync(item);
                }
            }

            if (input.AreaId == 374444736143429) //一楼平库
            {
                var wareLocationList = await _wareLocationRep.DetachedEntities.Where(u => u.AreaID == input.AreaId).ToListAsync();

                foreach (var item in wareLocationList)
                {
                    // 承重
                    if (item.LayerNo == 1 || item.LayerNo == 2 || item.LayerNo == 3) //1、2、3层：1.5T
                    {
                        item.Heavy = "1.5T";
                    }
                    else if (item.LayerNo == 4) //4层：1.2T
                    {
                        item.Heavy = "1.2T";
                    }
                    //if (item.LayerNo == 5) //5层：0.9T
                    else
                    {
                        item.Heavy = "0.9T";
                    }

                    // 高度、库位属性
                    if (item.LayerNo == 1) //1层：1200
                    {
                        item.High = 1200;
                        item.Attribute = "大";
                    }
                    else if (item.LayerNo == 2) //2层：1000
                    {
                        item.High = 1000;
                        item.Attribute = "中";
                    }
                    // if (item.LayerNo == 3 || item.LayerNo == 4 || item.LayerNo == 5) //3、4、5层：600
                    else
                    {
                        item.High = 600;
                        item.Attribute = "小";
                    }

                    await _wareLocationRep.UpdateAsync(item);
                }
            }
        }
    }
}
